//发布 - 订阅模式 （Publish-Subscribe Pattern, pub-sub）又叫观察者模式（Observer Pattern），它定义了一种一对多的关系，让多个订阅者对象同时监听某一个发布者，或者叫主题对象，这个主题对象的状态发生变化时就会通知所有订阅自己的订阅者对象，使得它们能够自动更新自己。
class Publisher{
    constructor(){
        this.map = {}
    }
    //订阅
    subscribe(type, cb){
        if(!this.map[type]){
            this.map[type] = []
        }
        if(!this.map[type].includes(cb)){
            this.map[type].push(cb)
        }
    }
    //取订
    unsubscribe(type, cb){
        if(!this.map[type] || !this.map[type].includes(cb)) return
        const index = this.map[type].findIndexOf(cb)
        this.map[type].splic(index, 1)
    }
    //发布
    notify(type, ...arguments){
        if(!this.map[type]) return
        this.map[type].forEach((cb)=>{
            cb(...arguments)
        })
    }   
}

//甚至我们可以使用原生的 addEventListener、dispatchEvent、removeEventListener 来实现发布订阅：
const handler = (dom)=>{
    console.log('自定义方法', dom)
}
const app = document.querySelector('#app')
app.addEventListener('myevent', handler)
app.dispatchEvent(new Event('myevent'))

//Vue2中
const bus = new Vue()
bus.$on('change', hander) 
bus.$emit('change', data)

//vue2源码中
Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter() {
        // ...
        const value = getter ? getter.call(obj) : val // 如果原本对象拥有getter方法则执行
        dep.depend()                     // 进行依赖收集，dep.addSub
        return value
    },
    set: function reactiveSetter(newVal) {
        // ...
        if (setter) { setter.call(obj, newVal) }    // 如果原本对象拥有setter方法则执行
        dep.notify()               // 如果发生变更，则通知更新
    }
})

//vue3中
const reactive = (obj)=>{
    return new Proxy(obj, {
        get(target, key){
            const result = Reflect(...arguments)
            track(target, key)//订阅
            return isObj(result) ? reactive(result) : result
        },
        set(target, key, value){
            const result = Reflect(...arguments)
            trigger(target, key)//发布
            return result
        }
    })
}